package fr.lelouet.monitoring.datahandlers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.lelouet.monitoring.DataHandler;
import fr.lelouet.monitoring.perf.Tools;
import fr.lelouet.monitoring.snapshot.HVSnapshot;
import fr.lelouet.monitoring.snapshot.SnapshotReceiver;
import fr.lelouet.monitoring.snapshot.VMSnapshot;
import fr.lelouet.monitoring.snapshot.receivers.LoggerReceiver;

/**
 * handles incoming data by modifying a Snapshot according to the element the
 * data refers to.<br />
 * any data received is supposed to refer to the same hypervisor.
 */
public class SnapshotDataHandler implements DataHandler {

	public static final String CONVERT_TIMERELATIVE_KEY = "snapshot.timeRelative";

	public static final String SNAPSHOTRECEIVERS_KEY = "snapshot.receivers";

	protected boolean convert_timerelative = true;

	private static final Logger logger = LoggerFactory
			.getLogger(SnapshotDataHandler.class);

	@Override
	public void configure(Properties prop) {
		receivers.clear();
		for (String mclass : prop.getProperty(SNAPSHOTRECEIVERS_KEY,
				LoggerReceiver.class.getCanonicalName()).split(" ")) {
			try {
				if (mclass.length() > 0) {
					SnapshotReceiver receiver = (SnapshotReceiver) Class
							.forName(mclass).newInstance();
					logger.info("SnapshotDataHandler added receiver : "
							+ mclass);
					receivers.add(receiver);
				}
			} catch (Exception e) {
				logger.error(e.toString());
			}
		}
		for (SnapshotReceiver receiver : receivers) {
			receiver.configure(prop);
		}
		convert_timerelative = Boolean.parseBoolean(prop.getProperty(
				CONVERT_TIMERELATIVE_KEY, "" + true));
	}

	protected List<SnapshotReceiver> receivers = new ArrayList<SnapshotReceiver>(
			Arrays.asList(new SnapshotReceiver[] { new LoggerReceiver() }));

	public void setReceivers(List<SnapshotReceiver> receivers) {
		this.receivers = receivers;
	}

	@Override
	synchronized public void handle(Map<String, String> data) {
		if (convert_timerelative) {
			Map<String, String> converted = Tools.toTimeProportionnal(data);
			if (converted != null) {
				data = converted;
			}
		}
		// may watch several hypervisors, so need to know which own the element
		// the data refers to
		HVSnapshot hypervisor = getHVSnapshot(data);
		if (hypervisor == null) {
			return;
		}
		VMSnapshot modifiedVM = hypervisor.update(data);
		for (SnapshotReceiver receiver : receivers) {
			if (modifiedVM == null) {
				receiver.hypervisorModification(hypervisor);
			} else {
				receiver.vmModification(modifiedVM, hypervisor);
			}
		}
	}

	/** object Ids -> Snapshot that owns that object */
	protected Map<String, HVSnapshot> snapshots = new HashMap<String, HVSnapshot>();

	/**
	 * @param data
	 *            the informations about an object we want to know which
	 *            hypervisor owns it
	 * @return
	 */
	protected HVSnapshot getHVSnapshot(Map<String, String> data) {
		String HVId = data.get(fr.lelouet.monitoring.perf.Tools.HVIdKEY);
		if (HVId == null) {
			return null;
		}
		HVSnapshot ret = snapshots.get(HVId);
		if (ret == null) {
			ret = new HVSnapshot(HVId);
			snapshots.put(HVId, ret);
		}
		return ret;
	}

}
